package com.echoclient.mutiClient;


import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author: jia
 * @Descirption:
 * @Date: 2018/5/3 11:25
 * @Modified By:多连接客户端
 */


public class MutiClient {
    /**
     * 服务类
     */
    private Bootstrap bootstrap = new Bootstrap();
    /**
     * 会话
     */
    private List<Channel> channels = new ArrayList<>();
    /**
     * 引用计数器
     */
    private final AtomicInteger index = new AtomicInteger();

    private final String host = "localhost";
    private final int port = 10101;

    /**
     * 初始化方法
     */

    public void init(int count) throws InterruptedException {
        //创建线程池
        EventLoopGroup worker = new NioEventLoopGroup();
        //设置线程池
        bootstrap.group(worker)
                .channel(NioSocketChannel.class)
                .remoteAddress(host, port)
                .handler(new ChannelInitializer<Channel>() {
                    @Override
                    public void initChannel(Channel ch) throws Exception {
                        ch.pipeline().addLast(new MutiClientHandler());
                        ch.pipeline().addLast(new StringDecoder());
                        ch.pipeline().addLast(new StringEncoder());
                    }
                });
        //批量加入会话
        for (int i = 0; i < count; i++) {
            ChannelFuture future = bootstrap.connect().sync();
            channels.add(future.channel());

        }
    }

    /**
     * 获取会话
     */
    public Channel nextChannel() {
        return getFirstActiveChannel(0);
    }

    /**
     * 均匀获取第一个可用的会话
     * count为失败获取的次数，默认为0，如果获取的连接为
     * 不可用连接，则count+1
     */
    public Channel getFirstActiveChannel(int count) {
        Channel channel = channels.get(Math.abs(index.getAndDecrement() % channels.size()));
        //如果断开连接，重连
        if (!channel.isActive()) {
            //重连
            reconnect(channel);
            if (count >= channels.size()) {
                throw new RuntimeException("no can use channel!");
            }
            return getFirstActiveChannel(count + 1);
        }
        return channel;
    }

    /**
     * 重连,以下是
     * TODO 这里用锁并不好，使用队列比较好
     */
    private void reconnect(Channel channel) {
        synchronized (channel) {
            //如果不存在，不能重连
            if (channels.indexOf(channel) == -1) {
                return;
            }
            //如果存在重新设置一个新连接
            Channel newChannel = null;
            try {
                ChannelFuture fu = bootstrap.connect().sync();
                newChannel = fu.channel();
                channels.set(channels.indexOf(channel), newChannel);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }


}
